﻿using Microsoft.Phone.Controls;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace Site2AppWP8.Template.XHR
{
    public static class LocalXHRInterceptor
    {

        private static void SendDataBackToInterceptor(WebBrowser webView, string receptor, string responseString)
        {
            webView.InvokeScript(receptor, responseString);
        }

        public async static void Intercept(dynamic order, WebBrowser webView, object uriResolver)
        {
            string orderUrl = order.url;

            int index = orderUrl.LastIndexOf("http");
            if (index > -1)
            {
                order.url = orderUrl.Substring(index);
                orderUrl = order.url;
            }

            var oReq = new HttpClient();

            string methodString = (order.method != null) ? order.method.Value : String.Empty;
            string orderBody = (order.body != null) ? order.body.Value : String.Empty;

            HttpMethod method = new HttpMethod(methodString);

            HttpRequestMessage requestMessage = new HttpRequestMessage(method, orderUrl);

            if (!String.IsNullOrEmpty(orderBody))
            {
                StringContent orderBodyContent = new StringContent(orderBody);
                requestMessage.Content = orderBodyContent;
            }

            var headers = order.headers as JObject;

            SetRequestHeaders(oReq, requestMessage, headers);
                        
            HttpResponseMessage responseMessage = await oReq.SendAsync(requestMessage);

            string contentString = await responseMessage.Content.ReadAsStringAsync();
            contentString = contentString.Replace("\"", "\\\"").Replace("\n", "\\n");

            StringBuilder responseHeaders = new StringBuilder();

            foreach (var header in responseMessage.Content.Headers)
            {
                responseHeaders.Append(String.Format("{0}:{1}\\r\\n", header.Key, header.Value.FirstOrDefault()));
            }

            string responseHeaderString = responseHeaders.ToString();

            StringBuilder responseString = new StringBuilder();

            responseString.Append("{\"response\":\"" + contentString + "\",");
            responseString.Append("\"responseText\":\"" + contentString + "\",");
            responseString.Append("\"responseType\":\"\",");
            responseString.Append("\"responseXML\":{},");
            responseString.Append("\"statusText\":\"" + responseMessage.ReasonPhrase + "\",");
            responseString.Append("\"callbackId\":\"" + order.callbackId + "\",");
            responseString.Append("\"responseHeaders\":\"" + responseHeaderString + "\"}");

            SendDataBackToInterceptor(webView, "getXhrCallbacks", responseString.ToString());
        }

        private static void SetRequestHeaders(HttpClient oReq, HttpRequestMessage requestMessage, JObject headers)
        {
            if (headers != null)
            {
                foreach (var token in headers.Children())
                {
                    if (token is JProperty)
                    {
                        var property = token as JProperty;

                        if (property.Value != null)
                        {
                            try
                            {
                                Debug.WriteLine("Adding Header. Key:{0}, Value:{1}", property.Name, property.Value.Value<string>());
                                switch(property.Name)
                                {
                                    case "Accept":
                                        requestMessage.Headers.TryAddWithoutValidation(property.Name, property.Value.Value<string>());
                                        break;
                                    case "Content-Type":
                                        if (requestMessage.Content != null)
                                        {
                                            requestMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(property.Value.Value<string>());
                                        }
                                        else
                                        {
                                            TryDynamicHeaderAdd(oReq, property);
                                        }
                                        break;
                                    default:
                                        TryDynamicHeaderAdd(oReq, property);
                                        break;
                                }
                            }
                            catch(InvalidOperationException)
                            {
                                TryDynamicHeaderAdd(oReq, property);
                            }
                        }
                    }
                }
            }
        }

        private static void TryDynamicHeaderAdd(HttpClient oReq, JProperty property)
        {
            Debug.WriteLine("Failed to add header:{0} with value:{1}. Trying again...", property.Name, property.Value.Value<string>());
            bool headerAdded = oReq.DefaultRequestHeaders.TryAddWithoutValidation(property.Name, property.Value.Value<string>());
            if (!headerAdded)
            {
                Debug.WriteLine("Failed to add header:{0} with value:{1}.", property.Name, property.Value.Value<string>());
            }
            else
            {
                Debug.WriteLine("Header added. Key:{0}, Value:{1}", property.Name, property.Value.Value<string>());
            }
        }
    }
}
